package com.fs.uc.core.permcheck;

import com.fs.uc.base.domain.*;
import com.fs.uc.base.repo.AdditionalRoleRepository;
import com.fs.uc.base.repo.PersonRepository;
import com.fs.uc.base.repo.RoleRepository;
import com.fs.uc.core.CacheName;
import io.quarkus.cache.CacheResult;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author 崔超
 * 2021/12/9
 */
@ApplicationScoped
class PersonPermissionChecker implements IPermissionChecker {

    @Inject
    PersonRepository personRepo;
    @Inject
    AdditionalRoleRepository additionalRoleRepo;
    @Inject
    RoleRepository roleRepo;

    @Override
    public boolean checkPermission(Long personId, String action, String resource) {
        Set<Permission> permOfOrgUser = getPermissions(personId);
        return PermissionCompare.comparePermissions(action, resource, permOfOrgUser);
    }

    @CacheResult(cacheName = CacheName.PERSON_PERMISSION)
    @Override
    public Set<Permission> getPermissions(Long personId) {
        Set<Role> roles = getRoles(personId);
        Set<Permission> permissions = new HashSet<>();

        for (Role role : roles) {
            permissions.addAll(role.permissions);
        }
        return permissions;
    }

    @Override
    public Set<Role> getRoles(Long personId) {
        //添加注册用户角色（访客、车主)
        List<Role> roles = roleRepo.findByType(RoleType.RegisteredUserOriented);
        Set<Role> personRoles = new HashSet<>(roles);

        //额外角色
        Person person = personRepo.getById(personId);
        if (person.currentOrg != null) {
            List<Long> roleIds = additionalRoleRepo.findRoleIds(person.currentOrg.id, person.id);
            List<Role> additionRoles = roleRepo.findByIds(roleIds);
            personRoles.addAll(additionRoles);
        }

        Set<FunctionalModule> authorizedModules = getAuthorizedModule(personId);
        //模块下的所有角色
        HashSet<Role> openModuleRoles = authorizedModules.stream().reduce(new HashSet<>(),
                (roleSet, module) -> {
                    roleSet.addAll(module.roles);
                    return roleSet;
                }
                , (roleSet1, roleSet2) -> {
                    roleSet1.addAll(roleSet2);
                    return roleSet1;
                });

        //添加园区人员角色
        openModuleRoles.stream()
                .filter(role -> role.type == RoleType.CommonUser)
                .forEach(personRoles::add);

        //如果person属于其当前组织的管理者，添加管理者角色
        Org personCurOrg = person.currentOrg;
        if (personCurOrg != null && person.manageOrgs.contains(personCurOrg)) {

            if (personCurOrg.type == OrgType.Park) {
                //园区管理员
                openModuleRoles.stream()
                        .filter(role -> role.type == RoleType.ParkOriented)
                        .forEach(personRoles::add);
            } else {
                //企业管理员
                openModuleRoles.stream()
                        .filter(role -> role.type == RoleType.EnterpriseOriented)
                        .forEach(personRoles::add);
            }
        }

        return personRoles;
    }

    @Override
    public Set<FunctionalModule> getAuthorizedModule(Long personId) {
        Person person = personRepo.getById(personId);
        if (person.currentOrg == null) {
            return new HashSet<>();
        }
        Set<FunctionalModule> sets = new HashSet<>(person.currentOrg.functionalModules);
        if (person.currentOrg.parent != null) {
            sets.addAll(person.currentOrg.parent.functionalModules);
        }
        return sets;
    }

    @CacheResult(cacheName = CacheName.PERSON_SUBJECT)
    @Override
    public SubjectInfo getSubjectInfo(Long personId) {
        Person person = personRepo.getById(personId);
        Org currentOrg = person.currentOrg;
        if (currentOrg == null) {
            return new SubjectInfo(0L, 0L, person.id, person.name);
        }

        if (currentOrg.type == OrgType.Park) {
            return new SubjectInfo(currentOrg.id, currentOrg.id, person.id, person.name);
        } else {
            if (currentOrg.parent == null) {
                return new SubjectInfo(0L, currentOrg.id, person.id, person.name);
            } else {
                return new SubjectInfo(currentOrg.parent.id, currentOrg.id, person.id, person.name);
            }
        }
    }
}
